/***************************************************************************
*   Copyright (C) 2009 by stefan,,,                                       *
*   stefan.w.ggb@gmail.com                                                *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
*   This program is distributed in the hope that it will be useful,       *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*   GNU General Public License for more details.                          *
*                                                                         *
*   You should have received a copy of the GNU General Public License     *
*   along with this program; if not, write to the                         *
*   Free Software Foundation, Inc.,                                       *
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
***************************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include "dlinkedlist.h"

struct DLinkedList* 
createDLinkedList() {
	struct DLinkedList *list = malloc(sizeof(struct DLinkedList));
	struct DEntry *dummy = malloc(sizeof(struct DEntry));
	
	dummy->data = NULL;
	dummy->next = dummy;
	dummy->previous = dummy;
	
	list->size = 0;
	list->dummy = dummy;
	
	list->deleteDLinkedList = _swr_list_deleteDLinkedList;
	list->addElement = _swr_list_addElement;
	list->addFirst = _swr_list_addFirst;
	list->addLast = _swr_list_addLast;
	list->addAtPosition = _swr_list_addAtPosition;
	list->removeElement = _swr_list_removeElement;
	list->removeFirst = _swr_list_removeFirst;
	list->removeLast = _swr_list_removeLast;
	list->removeAtPosition = _swr_list_removeAtPosition;
	list->getElement = _swr_list_getElement;
	list->getFirst = _swr_list_getFirst;
	list->getLast = _swr_list_getLast;
	list->indexOf = _swr_list_indexOf;
	list->getSize = _swr_list_getSize;
	
	return list;
}

int 
_swr_list_deleteDLinkedList(struct DLinkedList* list) {
	struct DEntry *current = list->dummy->next;
	struct DEntry *next = current->next;
	
	while(current != list->dummy) {
		next = current->next;
		free(current);
		current = next;
	}
	
	free(list->dummy);
	free(list);
	
	return 0;
}


int 
_swr_list_addElement(struct DLinkedList* list, char* data) {
	return list->addLast(list, data);
}


char*  
_swr_list_removeElement(struct DLinkedList* list, char* data) {
	int position = list->indexOf(list, data);
	return list->removeAtPosition(list, position);
}

int 
_swr_list_addAtPosition(struct DLinkedList* list, int position, char* data) {
	struct DEntry *newEntry = malloc(sizeof(struct DEntry));
	struct DEntry *prevEntry;
	struct DEntry *nextEntry;
	
	int i;
	
	if(position > list->size) {
		return -1;
	}
	
	nextEntry = list->dummy->next;
	
	for(i = 0; i < position; i++) {
		nextEntry = nextEntry->next;
	}
	
	prevEntry = nextEntry->previous;
	
	newEntry->data = data;
	
	prevEntry->next = newEntry;
	newEntry->previous = prevEntry;
	
	newEntry->next = nextEntry;
	nextEntry->previous = newEntry;	
	
	list->size++;
	return i;
}

char* 
_swr_list_removeAtPosition(struct DLinkedList* list, int position) {
	struct DEntry* remEntry;
	struct DEntry* prevEntry;
	struct DEntry* nextEntry;
	char* data;
	
	if(position >= list->size) {
		return NULL;
	}
	
	remEntry = _swr_list_getEntry(list, position);
	prevEntry = remEntry->previous;
	nextEntry = remEntry->next;
	
	data = remEntry->data;
	free(remEntry);
	prevEntry->next = nextEntry;
	nextEntry->previous = prevEntry;
	
	list->size--;	
	return data;
}

int 
_swr_list_addFirst(struct DLinkedList* list, char* data) {
	return list->addAtPosition(list, 0, data);
} 

char*  
_swr_list_removeFirst(struct DLinkedList* list) {
	return list->removeAtPosition(list, 0);
}

int 
_swr_list_addLast(struct DLinkedList* list, char* data) {
	return list->addAtPosition(list, list->size, data);
}

char*  
_swr_list_removeLast(struct DLinkedList* list) {
	return list->removeAtPosition(list, list->size-1);
}


char* 
_swr_list_getElement(struct DLinkedList* list, int position) {
	return _swr_list_getEntry(list, position)->data;	
}

struct DEntry*
_swr_list_getEntry(struct DLinkedList* list, int position) {
	struct DEntry *current = list->dummy->next;
	
	int i;
	
	if(position >= list->size) {
		return NULL;
	}
	
	for(i = 0; i < position; i++) {
		current = current->next;
	}
	
	return current;
}

char* 
_swr_list_getFirst(struct DLinkedList* list) {
	return list->getElement(list, 0);
}	

char* 
_swr_list_getLast(struct DLinkedList* list) {
	return list->getElement(list, list->size-1);
}	

int 
_swr_list_indexOf(struct DLinkedList* list, char* data) {
	struct DEntry* current;
	int position;
	for(current = list->dummy->next, position = 0; current != list->dummy; current = current->next, position++) {
		if(current->data == data) {
			return position;
		}
	}
	return -1;
}

int 
_swr_list_getSize(struct DLinkedList* list) {
	return list->size;
}